﻿using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Drawing;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.Windows.Forms;
using HtmlAgilityPack;
using HtmlDocument = HtmlAgilityPack.HtmlDocument;
using System.IO;
using ExtractionTool.Data;

namespace ExtractionTool
{
    public partial class MainForm : Form
    {
        public MainForm()
        {
            InitializeComponent();
            
            //using(BankingEntities db = new BankingEntities())
            //{
            //    db.Database.Create();
            //    db.SaveChanges();
            //}

            int rowsAffected = 0;

            DirectoryInfo rootFolder = new DirectoryInfo(@"C:\Users\Jason\Desktop\2013 Statements (HTML)\");
            foreach (FileInfo file in rootFolder.GetFiles("*.html", SearchOption.TopDirectoryOnly))
            {
                rowsAffected += testMethod(file.FullName);
            }

            string gg = "";
        }

        private int testMethod(string filePath)
        {
            int rowsAffected = 0;
            BankingEntities db = new BankingEntities();

            // String filePath = @"C:\Users\Jason\Desktop\2013 Statements (HTML)\2012.12.21-2013.01.22.html";
            String fileContents = File.ReadAllText(filePath);
            fileContents = fileContents
                .Replace("\r", String.Empty)
                .Replace("\n", String.Empty)
                .Replace("\t", String.Empty);

            HtmlDocument hDoc = new HtmlDocument();
            hDoc.OptionFixNestedTags = true;
            hDoc.LoadHtml(fileContents);

            HtmlNodeCollection divNodes = hDoc
                .DocumentNode
                .SelectSingleNode("//body")
                .FirstChild
                .ChildNodes;

            for (int i = 0; i < divNodes.Count; i++)
            {
                var columnData = getData(divNodes[i]);
                #region [ Deposits and Other Additions ]
                if (columnData.Any(c => c.Contains("Deposits and Other Additions")))
                {
                    while(true && i < divNodes.Count)
                    {
                        var data = getData(divNodes[i + 1]);
                        if (data.Count == 0)
                        {
                            i += 1;
                            continue;
                        }

                        DateTime txnDate = DateTime.Now;
                        if(DateTime.TryParse(data[0] + "/2013", out txnDate))
                        {
                            Transaction txn = new Transaction()
                            {
                                Timestamp = txnDate,
                                Amount = Decimal.Parse(data[1])
                            };

                            string description = data[2];
                            var map = db.VendorMaps.FirstOrDefault(v =>
                                v.Description == description);

                            if(map != null)
                                txn.Vendor = map.Vendor;
                            else
                            {
                                Vendor vendor = new Vendor()
                                {
                                    Name = data[2],
                                    Type = 0
                                };
                                db.Vendors.Add(vendor);

                                VendorMap vMap = new VendorMap()
                                {
                                    Description = vendor.Name,
                                    Vendor = vendor
                                };
                                db.VendorMaps.Add(vMap);

                                txn.Vendor = vendor;
                            }

                            i += 1;

                            var peek = getData(divNodes[i + 1]);
                            DateTime nextDate = DateTime.Now;
                            if(peek.Any(p => p.StartsWith("Checks")))
                            {
                                db.Transactions.Add(txn);
                                i += 1;

                                break;
                            }
                            else if (!DateTime.TryParse(peek[0] + "/2013", out nextDate) && peek.Count() == 1)
                            {
                                txn.Notes = peek[0];
                                db.Transactions.Add(txn);
                                i += 1;
                            }
                        }
                        else
                        {
                            i += 1;
                        }
                    }
                }
                #endregion
                #region [ Checks and Substitute Checks ]
                else if (columnData.Any(c => c.Contains("Checks and Substitute Checks")))
                {
                    while (true && i < divNodes.Count)
                    {
                        var data = getData(divNodes[i + 1]);
                        if (data.Count == 0)
                        {
                            i += 1;
                            continue;
                        }

                        int checkNum = -1;
                        if (int.TryParse(data[0], out checkNum))
                        {
                            Transaction txn = new Transaction()
                            {
                                Timestamp = DateTime.Parse(data[2] + "/2013"),
                                Amount = Decimal.Parse(data[1]),
                                Notes = data[0] + "(" + data[3] + ")"
                            };

                            string description = "Check";
                            var map = db.VendorMaps.FirstOrDefault(v =>
                                v.Description == description);

                            if (map != null)
                                txn.Vendor = map.Vendor;
                            else
                            {
                                Vendor vendor = new Vendor()
                                {
                                    Name = "Check",
                                    Type = 0
                                };
                                db.Vendors.Add(vendor);

                                VendorMap vMap = new VendorMap()
                                {
                                    Description = vendor.Name,
                                    Vendor = vendor
                                };
                                db.VendorMaps.Add(vMap);

                                txn.Vendor = vendor;
                            }

                            i += 1;

                            var peek = getData(divNodes[i + 1]);
                            if (peek.Any(p => p.StartsWith("Banking")))
                            {
                                db.Transactions.Add(txn);
                                i += 1;

                                break;
                            }
                        }
                        else
                            i += 1;
                    }
                }
                #endregion
                #region [ Banking/Check Card Withdrawals and Purchases ]
                else if (columnData.Any(c => c.Contains("Banking/Check Card Withdrawals and Purchases")))
                {
                    while (true && (i + 1) < divNodes.Count)
                    {
                        var data = getData(divNodes[i + 1]);
                        if (data.Count == 0 || data.Count > 3)
                        {
                            i += 1;
                            continue;
                        }

                        DateTime txnDate = DateTime.Now;
                        if (DateTime.TryParse(data[0] + "/2013", out txnDate))
                        {
                            Transaction txn = new Transaction()
                            {
                                Timestamp = txnDate,
                                Amount = Decimal.Parse(data[1])
                            };

                            string description = data[2];
                            var map = db.VendorMaps.FirstOrDefault(v =>
                                v.Description == description);

                            if (map != null)
                                txn.Vendor = map.Vendor;
                            else
                            {
                                Vendor vendor = new Vendor()
                                {
                                    Name = data[2],
                                    Type = 0
                                };
                                db.Vendors.Add(vendor);

                                VendorMap vMap = new VendorMap()
                                {
                                    Description = vendor.Name,
                                    Vendor = vendor
                                };
                                db.VendorMaps.Add(vMap);

                                txn.Vendor = vendor;
                            }

                            i += 1;

                            var peek = getData(divNodes[i + 1]);
                            DateTime nextDate = DateTime.Now;
                            if (peek.Any(p => p.StartsWith("Online")))
                            {
                                db.Transactions.Add(txn);
                                i += 1;

                                break;
                            }
                            else if (!DateTime.TryParse(peek[0] + "/2013", out nextDate) && peek.Count() == 1)
                            {
                                txn.Notes = peek[0];
                                db.Transactions.Add(txn);
                                i += 1;
                            }
                        }
                        else
                        {
                            i += 1;
                        }
                    }
                }                
                #endregion
                #region [ Online and Electronic Banking Deductions ]
                else if (columnData.Any(c => c.Contains("Online and Electronic Banking Deductions")))
                {
                    while (true && i < divNodes.Count)
                    {
                        var data = getData(divNodes[i + 1]);
                        if (data.Count == 0)
                        {
                            i += 1;
                            continue;
                        }

                        DateTime txnDate = DateTime.Now;
                        if (DateTime.TryParse(data[0] + "/2013", out txnDate))
                        {
                            Transaction txn = new Transaction()
                            {
                                Timestamp = txnDate,
                                Amount = Decimal.Parse(data[1])
                            };

                            string description = data[2];
                            var map = db.VendorMaps.FirstOrDefault(v =>
                                v.Description == description);

                            if (map != null)
                                txn.Vendor = map.Vendor;
                            else
                            {
                                Vendor vendor = new Vendor()
                                {
                                    Name = data[2],
                                    Type = 0
                                };
                                db.Vendors.Add(vendor);

                                VendorMap vMap = new VendorMap()
                                {
                                    Description = vendor.Name,
                                    Vendor = vendor
                                };
                                db.VendorMaps.Add(vMap);

                                txn.Vendor = vendor;
                            }

                            i += 1;

                            var peek = getData(divNodes[i + 1]);
                            DateTime nextDate = DateTime.Now;
                            if (peek.Any(p => p.StartsWith("Daily")))
                            {
                                db.Transactions.Add(txn);
                                i += 1;

                                break;
                            }
                            else if (!DateTime.TryParse(peek[0] + "/2013", out nextDate) && peek.Count() == 1)
                            {
                                txn.Notes = peek[0];
                                db.Transactions.Add(txn);
                                i += 1;
                            }
                        }
                        else
                        {
                            i += 1;
                        }
                    }
                }                
                #endregion
            }

            rowsAffected = db.SaveChanges();
            db.Dispose();

            return rowsAffected;
        }

        private List<string> getData(HtmlNode node)
        {
            if (node.HasChildNodes)
            {
                return node.FirstChild.ChildNodes
                    .Select(n => n.InnerText)
                    .Where(n => !String.IsNullOrWhiteSpace(n))
                    .ToList();
            }
            else
                return new List<string>();
        }
    }
}
